﻿#region Using

using System.Collections.Generic;
using System.Linq;

using Common.Base;
using Common.Enums;

using CommunicationLibrary.TransportData;

using GameCommon.Args;
using GameCommon.Base;
using GameCommon.Effects;
using GameCommon.HitBoxes;

using GameGraphics.Components;
using GameGraphics.Enums;
using GameGraphics.Helper;
using GameGraphics.Screens.HUD;

using GameNetwork;
using GameNetwork.Interfaces;

using Microsoft.Xna.Framework;

using GameComponent = GameCommon.Components.GameComponent;
using RouteTypeEnum = GameNetwork.Network.RouteTypeEnum;

#endregion

namespace GameGraphics.Screens.GameBoard
{
    public class GameBoard : ScreenBase
    {
        private CameraManager cameraManager;

        private IGameNetwork network;

        private Dictionary<int, BoardTile> boardTiles;

        private BoardTile selectedTile;

        private GameModeEnum gameMode;

        private Hud hud;

        public GameBoard(IScreenChanger changer, object argument)
            : base(changer, argument)
        {
            this.Layer = 2;
        }

        public override ScreenEnum Screen
        {
            get
            {
                return ScreenEnum.GameBoard;
            }
        }

        public override void Initialize()
        {
            base.Initialize();
            this.gameMode = GameModeEnum.Farmer;

            this.network = NetworkDistributor.GetGameNetwork();
            this.network.OnGameWon += this.GameWon;
            this.network.OnGameLost += this.GameLost;
            this.network.OnConnectionError += this.ConnectionError;
            
            this.hud = (Hud)this.AddScreen(ScreenEnum.Hud, new HudCommandEventHandler(this.HudCommandInvoked));
            this.AddScreen(ScreenEnum.CloudScreen);

            this.AddCommand("Tile", this.OnTileClick);
        }

        public override void LoadContent()
        {
            base.LoadContent();

            this.InitializeCamera();
            this.BuildBoard();
        }

        public override void Update(GameTime gameTime)
        {
            this.cameraManager.UpdateCamera();
            base.Update(gameTime);

            BoardBuilder.Update(this.network.Player.Identifier, this.network.GetGameState().Tiles, this.boardTiles);
        }

        public override void Dispose()
        {
            base.Dispose();
            this.network.OnGameWon -= this.GameWon;
            this.network.OnGameLost -= this.GameLost;
            this.network.OnConnectionError -= this.ConnectionError;
        }

        protected override void OnMouseDraggedLeft(MouseDraggedArgs args)
        {
            BoardTile tileStart = null;
            BoardTile tileEnd = null;

            this.GetTiles(args, ref tileStart, ref tileEnd);

            if (tileStart != null && tileEnd != null && !tileStart.Equals(tileEnd))
            {
                var routeType = this.gameMode == GameModeEnum.Farmer ? RouteTypeEnum.Farmer : RouteTypeEnum.Militia;
                var result = this.network.NewRoute(routeType, tileStart.GridPosition, tileEnd.GridPosition);
                if (result.ResultType == ResultTypeEnum.Success)
                {
                    tileStart.AddRoute(tileEnd, routeType);
                }

                this.hud.AddMessage(result);
            }
        }

        protected override void OnMouseDraggedRight(MouseDraggedArgs args)
        {
            BoardTile tileStart = null;
            BoardTile tileEnd = null;

            this.GetTiles(args, ref tileStart, ref tileEnd);

            if (tileStart != null && tileEnd != null && !tileStart.Equals(tileEnd))
            {
                var routeType = this.gameMode == GameModeEnum.Farmer ? RouteTypeEnum.Farmer : RouteTypeEnum.Militia;
                var result = this.network.RemoveRoute(routeType, tileStart.GridPosition, tileEnd.GridPosition);
                if (result.ResultType == ResultTypeEnum.Success)
                {
                    tileStart.RemoveRoute(tileEnd.GridPosition, routeType);
                }

                this.hud.AddMessage(result);
            }
        }

        private void GetTiles(MouseDraggedArgs args, ref BoardTile tile1, ref BoardTile tile2)
        {
            foreach (var component in this.Components.OfType<BoardTile>())
            {
                var hitbox = component.HitBox;

                if (hitbox == null)
                {
                    continue;
                }

                if (hitbox.IsPointInHitbox(this.Camera.GetPosition(args.MousePressedPosition)))
                {
                    tile1 = component;
                }

                if (hitbox.IsPointInHitbox(this.Camera.GetPosition(args.MouseReleasedPosition)))
                {
                    tile2 = component;
                }

                if (tile1 != null && tile2 != null)
                {
                    break;
                }
            }
        }

        private void GameLost(Player player)
        {
            this.AddScreen(ScreenEnum.GameEndedOverlay, GameResultEnum.Lost);
            this.Disable();
        }

        private void GameWon(Player player)
        {
            this.Effects.Add(new GreyScale(1));
            this.AddScreen(ScreenEnum.GameEndedOverlay, GameResultEnum.Won);
            this.Disable();
        }

        private void BuildBoard()
        {
            this.boardTiles = BoardBuilder.BuildBoard(this.network.Player.Identifier, this.network.GetGameState().Tiles);

            foreach (var boardTile in this.boardTiles)
            {
                this.Components.Add(boardTile.Value);
            }
        }

        private void InitializeCamera()
        {
            this.Camera.X = -10;
            this.Camera.MaxX = 2000;
            this.Camera.MaxY = 2000;
            this.Camera.MinX = 0;
            this.Camera.MinY = -20;
            this.cameraManager = new CameraManager(this.Camera, 10, 15);
        }

        private void OnTileClick(GameComponent obj)
        {
            var tile = obj as BoardTile;
            if (tile == null)
            {
                return;
            }

            this.SelectTile(tile);
        }

        private void SelectTile(BoardTile tile)
        {
            if (this.selectedTile != null)
            {
                this.selectedTile.Deselect();
            }

            this.selectedTile = tile;
            this.selectedTile.Select();
        }

        private void HudCommandInvoked(HudCommandEnum gamemode)
        {
            switch (gamemode)
            {
                case HudCommandEnum.SwitchedToFarmerMode:
                    this.SwitchToFamerMode();
                    break;
                case HudCommandEnum.SwitchedToFighterMode:
                    this.SwitchToFighterMode();
                    break;
                case HudCommandEnum.BuildBarrack:
                    this.BuildBarrack();
                    break;
                case HudCommandEnum.BuildGoldMine:
                    this.BuildGoldMine();
                    break;
            }
        }

        private void BuildGoldMine()
        {
            if (this.selectedTile != null)
            {
                var result = this.network.BuildGoldMine(this.selectedTile.GridPosition);
                this.hud.AddMessage(result);
            }
        }

        private void BuildBarrack()
        {
            if (this.selectedTile != null)
            {
                var result = this.network.BuildBarrack(this.selectedTile.GridPosition);
                this.hud.AddMessage(result);
            }
        }

        private void SwitchToFighterMode()
        {
            foreach (var boardTile in this.boardTiles)
            {
                boardTile.Value.ShowFighterRoutes();
            }

            this.gameMode = GameModeEnum.Fighter;
        }

        private void SwitchToFamerMode()
        {
            foreach (var boardTile in this.boardTiles)
            {
                boardTile.Value.ShowFarmerRoutes();
            }

            this.gameMode = GameModeEnum.Farmer;
        }
        
        private void ConnectionError()
        {
            this.RemoveAnyScreen();
            this.AddScreen(ScreenEnum.MainMenu);
        }
    }
}